package skiree.host.abetsy.service.core.iqiyi;

import cn.hutool.core.img.ColorUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.XmlUtil;
import cn.hutool.http.HttpUtil;
import com.vdurmont.emoji.EmojiParser;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import skiree.host.abetsy.dao.LocalCommentMapper;
import skiree.host.abetsy.dao.LocalEpisodeMapper;
import skiree.host.abetsy.model.LocalComment;
import skiree.host.abetsy.model.LocalEpisode;
import skiree.host.abetsy.service.core.Stratege;

import javax.annotation.Resource;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
public class iQiYiProcess implements Stratege {

    @Resource
    private LocalEpisodeMapper localEpisodeMapper;

    @Resource
    private LocalCommentMapper localCommentMapper;

    @Override
    public void loadDanMu(LocalEpisode localEpisodeOld) {
        // 先检查localEpisode状态
        LocalEpisode localEpisode = localEpisodeMapper.selectById(localEpisodeOld.getId());
        if (localEpisode.getStatus().equals("init")) {
            localEpisode.setStatus("loading");
            localEpisode.setTime(new Date());
            localEpisodeMapper.updateById(localEpisode);
            Node node = new Node();
            node.setUrl(localEpisode.getUrl());
            while (node.getDuration() == null || node.getId() == null) {
                try {
                    String resultInfo = HttpUtil.get(node.getUrl(), CharsetUtil.CHARSET_UTF_8);
                    Matcher matcher1 = Pattern.compile("\"videoDuration\":(\\d+),").matcher(resultInfo);
                    if (matcher1.find()) {
                        int duration = Integer.parseInt(matcher1.group(1));
                        node.setDuration(duration);
                    }
                    Matcher matcher2 = Pattern.compile("window\\.QiyiPlayerProphetData=\\{\"tvid\":(\\d+),").matcher(resultInfo);
                    if (matcher2.find()) {
                        String tvIdStr = matcher2.group(1);
                        node.setId(tvIdStr);
                    }
                } catch (Exception e) {
                    node.setDuration(null);
                    node.setId(null);
                    try {
                        Thread.sleep(1000L);
                    } catch (Exception ignore) {
                    }
                }
            }
            int i_length = (int) Math.ceil(node.getDuration() / 300);
            List<LocalComment> comments = new ArrayList<>();
            for (int i = 1; i < i_length + 1; i++) {
                String i_url = "https://cmts.iqiyi.com/bullet/" + node.getId().substring(node.getId().length() - 4, node.getId().length() - 2) + "/" + node.getId().substring(node.getId().length() - 2) + "/" + node.getId() + "_300_" + i + ".z";
                getExtraDanMu(comments, i_url, localEpisode);
            }
            // 时间相同的弹幕只保留三条
            comments = comments.stream().collect(Collectors.groupingBy(LocalComment::getT)).values().stream().flatMap(list -> list.stream().limit(3)).collect(Collectors.toList());
            localCommentMapper.insert(comments);
        }
    }

    public static void getExtraDanMu(List<LocalComment> comments, String url, LocalEpisode localEpisode) {
        try {
            String dmDecompressedString = new String(decompress(downloadData(url)), "UTF-8");
            Document document = XmlUtil.parseXml(dmDecompressedString);
            NodeList bulletInfoList = document.getDocumentElement().getElementsByTagName("bulletInfo");
            List<Element> bulletInfoElements = new ArrayList<>();
            for (int i = 0; i < bulletInfoList.getLength(); i++) {
                Element bulletInfoElement = (Element) bulletInfoList.item(i);
                bulletInfoElements.add(bulletInfoElement);
            }
            for (Element bulletInfoElement : bulletInfoElements) {
                String content = bulletInfoElement.getElementsByTagName("content").item(0).getTextContent();
                content = EmojiParser.removeAllEmojis(content);
                if (!content.isEmpty()) {
                    String showTime = bulletInfoElement.getElementsByTagName("showTime").item(0).getTextContent();
                    long offset = Long.parseLong(showTime);
                    BigDecimal start = new BigDecimal("0.00");
                    if (offset != 0) {
                        start = new BigDecimal(offset).divide(new BigDecimal(1), 2, RoundingMode.HALF_UP);
                    }
                    String time = start.toString();
                    String style = bulletInfoElement.getElementsByTagName("color").item(0).getTextContent();
                    try {
                        Color color = ColorUtil.hexToColor(style.toUpperCase());
                        style = String.valueOf((color.getRed() * 256 * 256) + (color.getGreen() * 256) + color.getBlue());
                    } catch (Exception e) {
                        style = "16777215";
                    }
                    String position = "1";
                    String userId = "[iqiyi]";
                    LocalComment localComment = new LocalComment();
                    localComment.setEpisodeId(localEpisode.getId());
                    localComment.setP(String.join(",", Arrays.asList(time, position, style, userId)));
                    localComment.setM(content);
                    localComment.setT(start);
                    comments.add(localComment);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("爱奇艺弹幕加载异常");
        }
    }

    public static byte[] downloadData(String url) throws IOException {
        URL dataUrl = new URL(url);
        HttpURLConnection connection = (HttpURLConnection) dataUrl.openConnection();
        connection.setRequestMethod("GET");
        try (InputStream inputStream = connection.getInputStream()) {
            return IOUtils.toByteArray(inputStream);
        }
    }

    public static byte[] decompress(byte[] compressedData) throws IOException, CompressorException {
        ByteArrayInputStream inputStream = new ByteArrayInputStream(compressedData);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try (InputStream decompressorStream = new CompressorStreamFactory().createCompressorInputStream(inputStream)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = decompressorStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
        return outputStream.toByteArray();
    }

    @Override
    public boolean supports(LocalEpisode localEpisode) {
        return localEpisode.getUrl().contains("www.iqiyi.com");
    }

}